<?php
namespace hamster\mongodb;

trait Query
{
	use BasicQuery;

	/**
	 * 分页查询
	 * @param int $page
	 * @param int $size
	 * @example db.user.find({'age':20}).skip(0).limit(10)
	 * @return array
	 */
	public function paginate($page=1, $size=10)
	{
		$collection = $this->collection;
		$bulk = self::$db->$collection;
		if ($bulk instanceof \MongoDB\Collection)

		// 【查询】
		$filter = self::$filter ?? [];
		$options = self::$options ?? [];
		$options['limit'] = $size;
		$options['skip'] = $size * ($page - 1);

		$cursor = $bulk->find($filter, $options); // 成功的话，返回一个\MongoDB\Driver\Cursor实例。

		$data = ['list'=>[], 'total'=>$this->count()];

		$this->_clear(); // （执行count()之前不能清除）

		if ($cursor instanceof \MongoDB\Driver\Cursor) {
			foreach ($cursor as $document) {
				$document = json_decode(json_encode($document), true);
				$document['id'] = $document['_id']['$oid'];
				$data['list'][] = $document;
			}
		}
		return $data;
	}

	/**
	 * 获取具有给定列值的数组
	 * @param string $column 作为数组的value
	 * @param null $key 作为数组的key
	 * @return array
	 */
	public function pluck($column, $key=null)
	{
		$data = $this->find()->toArray();

		$data = array_column($data, $column, $key);

		return $data;
	}

	/**
	 * 获取最大字段值
	 * @param string $column 被查询的字段
	 * @return mixed
	 */
	public function max($column)
	{
		$data = $this->field([$column])->sort([$column=>-1])->limit(1)->findOne()->toArray();

		$this->_clear();

		$key_data = $data[$column];
		return $key_data;
	}

	/**
	 * 获取最小字段值
	 * @param string $column 被查询的字段
	 * @return mixed
	 */
	public function min($column)
	{
		$data = $this->field([$column])->sort([$column=>1])->limit(1)->findOne()->toArray();

		$this->_clear();

		$key_data = $data[$column];
		return $key_data;
	}


	/**
	 * 数量加减
	 * @param string $column 更新字段（字段类型要求为number）
	 * @param int $num 加减数量（负数为减少）
	 * @return bool|int|null
	 */
	public function inc($column, $num=1)
	{
		$collection = $this->collection;
		$bulk = self::$db->$collection;
		if ($bulk instanceof \MongoDB\Collection)

		// 【更新】
		$filter = self::$filter ?? [];
		$result = $bulk->updateMany( // 成功的话，返回一个MongoDB\UpdateResult实例。
			$filter,
			['$inc' => [$column=>$num]]
		);

		$this->_clear();

		if ($count = $result->getModifiedCount()) {
			return $count;
		} else {
			return false;
		}
	}

	/**
	 * 通道计算
	 * （使用field()时需包含查询字段）
	 * @param string $operation ['sum'=>'计算总和', 'avg'=>'计算平均值', 'min'=>'最小值', 'max'=>'最大值', 'first'=>'最先一个文档', 'last'=>'最后一个文档']
	 * @param string|mixed $column 字段名（默认值把数量当1处理，只有sum的时候有意义，相当于count）
	 * @example db.mycol.aggregate([{$group : {_id : {name:'$name',age:'$age'}, num_tutorial : {$sum : 1}}}])
	 * @example db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
	 * @return array
	 */
	public function aggregateCount($operation, $column = 1)
	{
		$collection = $this->collection;
		$bulk = self::$db->$collection;
		if ($bulk instanceof \MongoDB\Collection)

		// 【aggregate】
		if (self::$groupBy) {
			$groupBy = [];
			foreach (self::$groupBy as $group) {
				$groupBy[$group] = '$' . $group;
			}
		}

		$pipeline = $this->_pipeline();
		$pipeline[] = ['$group' => ['_id' => null, 'num' => ['$'.$operation => '$'.$column]]];

		$cursor = $bulk->aggregate($pipeline);

		$data = [];
		foreach ($cursor as $document) { // ($cursor对象无法打印)
			$document = json_decode(json_encode($document), true);

			$item = $document;
			if ($document['_id'] && is_array($document['_id'])) {
				$item['_id'] = $document['_id']['$oid'];
			}
			$data[] = $item;
		}

		return $data;
	}

	/**
	 * 联表查询（只适用于左连接的一对一关系）
	 * （field()设置在此函数无效）
	 * @param string $from 需要连接的集合
	 * @param string $localField 在输入文档中的关联字段
	 * @param string $foreignField 需要在from集合中查找的字段
	 * @param string $as 关联数据输出的名字
	 * @return array
	 */
	public function lookup($from, $localField, $foreignField, $as='from_data')
	{
		$collection = $this->collection;
		$bulk = self::$db->$collection;
		if ($bulk instanceof \MongoDB\Collection)

		$pipeline = $this->_pipeline();
		$pipeline[] = [
			'$lookup' =>
				[
					'from' 			=> $from,
					'localField' 	=> $localField,
					'foreignField' 	=> $foreignField,
					'as' 			=> $as,
				]
		];

		$cursor = $bulk->aggregate($pipeline);

		$data = [];
		foreach ($cursor as $document) { // ($cursor对象无法打印)
			$document = json_decode(json_encode($document), true);

			$item = $document;
			if ($document['_id'] && is_array($document['_id'])) {
				$item['_id'] = $document['_id']['$oid'];
			}
			$data[] = $item;
		}

		return $data;
	}

	// 管道格式整理
	protected function _pipeline()
	{
		$filter = self::$filter ?? [];
		$limit 	= self::$options['limit'] ?? 20; // 默认20条
		$sort 	= self::$options['sort'] ?? ['_id'=>-1];
		$skip 	= self::$options['skip'] ?? 0; // 默认0

		$pipeline = [
			['$skip'  => $skip], // 先跳过开头数量，再控制展示数量
			['$limit' => $limit],
			['$sort'  => $sort],
		];
		if (isset(self::$options['projection'])) {
			array_unshift($pipeline, ['$project' => self::$options['projection']]);
		}
		if ($filter) {
			array_unshift($pipeline, ['$match' => $filter]);
		}

		return $pipeline;
	}

}
